use std::collections::HashMap;
use std::sync::{Arc, Mutex};
use serde::{Deserialize, Serialize};
use tokio::sync::mpsc;
use uuid::Uuid;
use chrono::{DateTime, Utc};
use super::ffmpeg_service::{FfmpegService, FfmpegError};

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct VideoInfo {
    pub file_path: String,
    pub file_size: u64,
    pub duration: Option<String>,
    pub bitrate: Option<String>,
    pub resolution: Option<String>,
    pub codec: Option<String>,
    pub fps: Option<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ProcessParams {
    pub format: String,
    pub quality: Option<u32>,
    pub bitrate: Option<u32>,
    pub resolution: Option<(u32, u32)>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ExtractParams {
    pub audio_format: String,
    pub bitrate: Option<u32>,
    pub sample_rate: Option<u32>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ProcessResult {
    pub task_id: String,
    pub status: ProcessStatus,
    pub progress: f32,
    pub output_path: Option<String>,
    pub error_message: Option<String>,
    pub start_time: DateTime<Utc>,
    pub end_time: Option<DateTime<Utc>>,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum ProcessStatus {
    Pending,
    Processing,
    Completed,
    Failed,
    Cancelled,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BatchTask {
    pub task_id: String,
    pub input_path: String,
    pub output_path: String,
    pub params: ProcessParams,
    pub status: ProcessStatus,
    pub progress: f32,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BatchResult {
    pub batch_id: String,
    pub total_tasks: usize,
    pub completed_tasks: usize,
    pub failed_tasks: usize,
    pub results: Vec<ProcessResult>,
}

pub struct VideoService {
    ffmpeg_service: FfmpegService,
    active_tasks: Arc<Mutex<HashMap<String, ProcessStatus>>>,
}

impl VideoService {
    pub fn new() -> Result<Self, FfmpegError> {
        let ffmpeg_service = FfmpegService::new()?;
        
        Ok(Self {
            ffmpeg_service,
            active_tasks: Arc::new(Mutex::new(HashMap::new())),
        })
    }
    
    pub async fn convert_video(
        &self,
        input_path: String,
        output_path: String,
        params: ProcessParams,
    ) -> Result<ProcessResult, FfmpegError> {
        let task_id = Uuid::new_v4().to_string();
        let start_time = Utc::now();
        
        // 创建初始结果
        let mut result = ProcessResult {
            task_id: task_id.clone(),
            status: ProcessStatus::Processing,
            progress: 0.0,
            output_path: Some(output_path.clone()),
            error_message: None,
            start_time,
            end_time: None,
        };
        
        // 添加到活动任务列表
        {
            let mut tasks = self.active_tasks.lock().unwrap();
            tasks.insert(task_id.clone(), ProcessStatus::Processing);
        }
        
        // 创建进度通道
        let (progress_tx, mut progress_rx) = mpsc::channel(10);
        
        // 在后台执行转换任务
        let ffmpeg_service = self.ffmpeg_service.clone();
        let input_path_clone = input_path.clone();
        let output_path_clone = output_path.clone();
        let params_clone = params.clone();
        let task_id_clone = task_id.clone();
        let active_tasks = self.active_tasks.clone();
        
        tokio::spawn(async move {
            let convert_result = ffmpeg_service.convert_video(
                &input_path_clone,
                &output_path_clone,
                &params_clone.format,
                params_clone.quality,
                params_clone.bitrate,
                params_clone.resolution,
                Some(progress_tx),
            ).await;
            
            // 更新任务状态
            let mut tasks = active_tasks.lock().unwrap();
            match convert_result {
                Ok(_) => {
                    tasks.insert(task_id_clone.clone(), ProcessStatus::Completed);
                }
                Err(_e) => {
                    tasks.insert(task_id_clone.clone(), ProcessStatus::Failed);
                }
            }
        });
        
        // 监听进度更新
        while let Some(progress) = progress_rx.recv().await {
            result.progress = progress.progress;
            
            if progress.progress >= 100.0 {
                result.status = ProcessStatus::Completed;
                result.end_time = Some(Utc::now());
                break;
            }
        }
        
        Ok(result)
    }
    
    pub async fn extract_audio(
        &self,
        video_path: String,
        audio_path: String,
        params: ExtractParams,
    ) -> Result<ProcessResult, FfmpegError> {
        let task_id = Uuid::new_v4().to_string();
        let start_time = Utc::now();
        
        let mut result = ProcessResult {
            task_id: task_id.clone(),
            status: ProcessStatus::Processing,
            progress: 0.0,
            output_path: Some(audio_path.clone()),
            error_message: None,
            start_time,
            end_time: None,
        };
        
        {
            let mut tasks = self.active_tasks.lock().unwrap();
            tasks.insert(task_id.clone(), ProcessStatus::Processing);
        }
        
        // 执行音频提取
        match self.ffmpeg_service.extract_audio(
            &video_path,
            &audio_path,
            &params.audio_format,
            params.bitrate,
            params.sample_rate,
        ).await {
            Ok(_) => {
                result.status = ProcessStatus::Completed;
                result.progress = 100.0;
                result.end_time = Some(Utc::now());
                
                let mut tasks = self.active_tasks.lock().unwrap();
                tasks.insert(task_id, ProcessStatus::Completed);
            }
            Err(e) => {
                result.status = ProcessStatus::Failed;
                result.error_message = Some(e.to_string());
                result.end_time = Some(Utc::now());
                
                let mut tasks = self.active_tasks.lock().unwrap();
                tasks.insert(task_id, ProcessStatus::Failed);
                
                return Err(e);
            }
        }
        
        Ok(result)
    }
    
    pub async fn get_video_info(&self, file_path: String) -> Result<VideoInfo, FfmpegError> {
        let info_value = self.ffmpeg_service.get_video_info(&file_path)?;
        
        let video_info = VideoInfo {
            file_path: file_path.clone(),
            file_size: info_value["file_size"].as_u64().unwrap_or(0),
            duration: info_value["duration"].as_str().map(|s| s.to_string()),
            bitrate: info_value["bitrate"].as_str().map(|s| s.to_string()),
            resolution: info_value["resolution"].as_str().map(|s| s.to_string()),
            codec: info_value["codec"].as_str().map(|s| s.to_string()),
            fps: info_value["fps"].as_str().map(|s| s.to_string()),
        };
        
        Ok(video_info)
    }
    
    pub async fn batch_process(
        &self,
        tasks: Vec<BatchTask>,
    ) -> Result<BatchResult, FfmpegError> {
        let batch_id = Uuid::new_v4().to_string();
        let mut results = Vec::new();
        let mut completed_tasks = 0;
        let mut failed_tasks = 0;
        
        for task in &tasks {
            let result = self.convert_video(
                task.input_path.clone(),
                task.output_path.clone(),
                task.params.clone(),
            ).await;

            match result {
                Ok(mut process_result) => {
                    process_result.progress = 100.0;
                    process_result.status = ProcessStatus::Completed;
                    results.push(process_result);
                    completed_tasks += 1;
                }
                Err(e) => {
                    let failed_result = ProcessResult {
                        task_id: task.task_id.clone(),
                        status: ProcessStatus::Failed,
                        progress: 0.0,
                        output_path: Some(task.output_path.clone()),
                        error_message: Some(e.to_string()),
                        start_time: Utc::now(),
                        end_time: Some(Utc::now()),
                    };
                    results.push(failed_result);
                    failed_tasks += 1;
                }
            }
        }
        
        let batch_result = BatchResult {
            batch_id,
            total_tasks: tasks.len(),
            completed_tasks,
            failed_tasks,
            results,
        };
        
        Ok(batch_result)
    }
    
    pub fn get_active_tasks(&self) -> HashMap<String, ProcessStatus> {
        self.active_tasks.lock().unwrap().clone()
    }
    
    pub fn cancel_task(&self, task_id: &str) -> bool {
        let mut tasks = self.active_tasks.lock().unwrap();
        if let Some(status) = tasks.get_mut(task_id) {
            if *status == ProcessStatus::Processing {
                *status = ProcessStatus::Cancelled;
                return true;
            }
        }
        false
    }
    
    pub fn get_supported_video_formats(&self) -> Vec<super::ffmpeg_service::VideoFormat> {
        FfmpegService::get_supported_video_formats()
    }
    
    pub fn get_supported_audio_formats(&self) -> Vec<super::ffmpeg_service::AudioFormat> {
        FfmpegService::get_supported_audio_formats()
    }

    pub fn get_ffmpeg_path(&self) -> &str {
        self.ffmpeg_service.get_ffmpeg_path()
    }

    pub fn get_ffmpeg_version(&self) -> Result<String, super::ffmpeg_service::FfmpegError> {
        self.ffmpeg_service.get_ffmpeg_version()
    }
}